package com.rtsapp.server.network.session.netty;

import com.rtsapp.server.network.session.SessionManager;
import io.netty.channel.Channel;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;

import com.rtsapp.server.logger.Logger;

import com.rtsapp.server.network.session.Session;
import com.rtsapp.server.network.session.SessionListener;

public class NettySessionManager implements SessionManager {
	
	private static final Logger LOGGER =com.rtsapp.server.logger.LoggerFactory.getLogger( SessionManager.class  );
	
	/**
	 * 按SessionId存储的Session
	 */
	private final ConcurrentMap<Long, Session> sessionsBySessionId = new ConcurrentHashMap<>( );
	
	/**
	 * 按RemoteId存储的Session
	 */
	private final ConcurrentMap<Long, Session> sessionsByRemoteId = new ConcurrentHashMap<>( );
	
	/**
	 * 按通道存储的Session
	 */
	private final ConcurrentMap< Channel, NettySession > sessionsByChannel = new ConcurrentHashMap<>( );
	
	
	private final AtomicInteger nextSessionId = new AtomicInteger( Integer.MIN_VALUE );
	
	
	private volatile int sessionLimit ;
	
	private final Session.SessionType sessionType;
	
	private volatile SessionListener sessionListener;
	
	public NettySessionManager(Session.SessionType sessionType  ){
		this.sessionType = sessionType;
	}
	

	/**
	 * 通过channel注册一个Session
	 * @param channel
	 * @return 返回新创建的Session
	 */
	public Session addSession( Channel channel ){

		if( channel == null ){
			LOGGER.error("[session] session 注册错误, 参数channel为空, 代码错误");
			return null;
		}

		NettySession session = new NettySession( this, channel, sessionType, nextSessionId.incrementAndGet() );

		// 断言必定第一次加入到Session
		NettySession oldSession = sessionsByChannel.putIfAbsent(channel, session);
		if(  oldSession == null ){

			LOGGER.debug("[session] channel 注册成功, channel.hasCode={}, sessionid={}, channel={}", channel.hashCode(), session.getSessionId(), channel);

			sessionsBySessionId.put(session.getSessionId(), session );

			if( sessionListener != null ){
				sessionListener.onSessionAdded( session, this );
			}

		}else{
			session = oldSession;
			LOGGER.error("[session] channel 注册错误,  已经有一个session关联到channel, channel.hashCode={}, oldSession.sessionId={},channel={} ", channel.hashCode(), oldSession.getSessionId(), channel);
		}

		return session;
	}


	/**
	 * 移除一个Session
	 * @param channel
	 */
	public void removeSession( Channel channel ) {
		if( channel == null ){
			LOGGER.error("[session] session 移除错误, 参数channel为空, 代码错误");
			return;
		}

		NettySession session = sessionsByChannel.remove(channel);

		if (session != null) {

			LOGGER.debug("[session] channel 移除成功, channel.hashCode={}, sessionId={},channel={}", channel.hashCode(), session.getSessionId(), channel);

			sessionsBySessionId.remove( session.getSessionId() );
			sessionsByRemoteId.remove( session.getRemoteId() );
			
			if( sessionListener != null ){
				sessionListener.onSessionRemoved(session, this);
			}

		}else{
			LOGGER.debug("[session] channel 移除失败, channel没有绑定的session, channel.hashCode={}, channel={}", channel.hashCode(), channel);
		}

	}


	public Session getSession( Channel channel ){
		return this.sessionsByChannel.get( channel );
	}



	@Override
	public int getSessionCount() {
		return sessionsByChannel.size( );
	}


	
	@Override
	public boolean canAccept( String ip, int port ){
		
		if( sessionsBySessionId.size() >= sessionLimit ){
			
			return false;
			
		}
		
		return true;
	}

	@Override
	public List<Session> getAllSessions(){
		return new ArrayList<Session>( sessionsBySessionId.values() );
	}
	
	
	@Override
	public void bindSessionRemoteId(Session session, long remoteId) {
		if( session != null ){
			
			//remote没有开启过
			assert( session.getRemoteId() < 0 );
			
			sessionsByRemoteId.put( remoteId, session );
		}
	}

	
	@Override
	public Session getSession(long sessionId) {
		return sessionsBySessionId.get( sessionId );
	}
	
	
	@Override
	public Session getSessionByRemoteId( long remoteId ){
		return sessionsByRemoteId.get( remoteId );
	}


	@Override
	public void broadcast(long remoteId, Object message) {
		
	}

	@Override
	public void pushMessage(long sessionId, Object message) {
		
	}


	public void setSessionLimit(int sessionLimit) {
		this.sessionLimit = sessionLimit;
	}


	public void setSessionListener( SessionListener sessionListener ) {
		this.sessionListener = sessionListener;
	}
	
}
